﻿//#define TRACE_PARSED_EVENTS

using System;
using System.Diagnostics;
using TI_BLE_HCI_ClientLib.HCIBaseEntities;
using TI_BLE_HCI_ClientLib.HCIEvents;

using Utilities;

namespace TI_BLE_HCI_ClientLib.HCIParsers
{
    public static partial class HCIEventParser
    {
        public static HCIEvent Parse(byte[] buffer)
        {
            try
            {
#if TRACE_PARSED_EVENTS
                
                DiagnosticLog.TraceInformation("HCIEventParser Parsing " + buffer.ToHexString());
#endif
                var evt = parseBuffer(buffer);

#if TRACE_PARSED_EVENTS
                if(evt!=null) DiagnosticLog.TraceInformation("HCIEventParser Parsed " + evt.GetType().ToString());
#endif
                return evt;
            }
            catch (Exception ex)
            {
                DiagnosticLog.TraceError("HCIEventParser Parsing ERROR : " + ex.ToString());

                return null;
            }
        }

        private static HCIEvent parseBuffer(byte[] buffer)
        {
            if (buffer.Length < 2) throw new ArgumentException("Buffer Length must be >= 2");

            switch (buffer[0])
            {
                case (byte)HCIEventEventCode.HCI_LE_ExtEvent:
                    return parseHCI_LE_ExtEvent(buffer);
            }

            return null;
        }

        private static HCIEvent parseHCI_LE_ExtEvent(byte[] buffer)
        {
            byte parsLen = buffer[1];
            ushort eventOpcode = (ushort)((buffer[3] << 8) + buffer[2]);

            switch (eventOpcode)
            {
                // GAP

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_HCI_Extension_CommandStatus:
                    return parseHCI_LE_ExtEvent_GAP_Command_Status(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_Device_Init_Done:
                    return parseHCI_LE_ExtEvent_GAP_Device_Init_Done(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_Device_Information:
                    return parseHCI_LE_ExtEvent_GAP_Device_Information(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_Device_Discovery_Done:
                    return parseHCI_LE_ExtEvent_GAP_Device_Discovery(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_Link_Established:
                    return parseHCI_LE_ExtEvent_GAP_Link_Established(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_Link_Terminated:
                    return parseHCI_LE_ExtEvent_GAP_Link_Terminated(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_Advert_Data_Update_Done:
                    return parseHCI_LE_ExtEvent_GAP_Advert_Data_Update_Done(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_Make_Discoverable_Done:
                    return parseHCI_LE_ExtEvent_GAP_Make_Discoverable_Done(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.GAP_End_Discoverable_Done:
                    return parseHCI_LE_ExtEvent_GAP_End_Discoverable(parsLen, buffer);

                // GATT
                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Error_Response:
                    return parseHCI_LE_ExtEvent_ATT_Error_Response(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Exchange_MTU_Request:
                    return parseHCI_LE_ExtEvent_ATT_Exchange_MTU_Request(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Read_Characteristic_Value_Response:
                    return parseHCI_LE_ExtEvent_ATT_Read_Characteristic_Value_Response(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Write_Characteristic_Value_Response:
                    return parseHCI_LE_ExtEvent_ATT_Write_Characteristic_Value_Response(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Handle_Value_Notification:
                    return parseHCI_LE_ExtEvent_ATT_Handle_Value_Notification(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Handle_Value_Indication:
                    return parseHCI_LE_ExtEvent_ATT_Handle_Value_Indication(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Read_Characteristic_Value_Request:
                    return parseHCI_LE_ExtEvent_ATT_Read_Characteristic_Value_Request(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Write_Characteristic_Value_Request:
                    return parseHCI_LE_ExtEvent_ATT_Write_Characteristic_Value_Request(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Prepare_Write_Characteristic_Value_Request:
                    return parseHCI_LE_ExtEvent_ATT_Prepare_Write_Characteristic_Value_Request(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Read_By_Group_Type_Request:
                    return parseHCI_LE_ExtEvent_ATT_Read_By_Group_Type_Request(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Read_By_Type_Request:
                    return parseHCI_LE_ExtEvent_ATT_Read_By_Type_Request(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Find_By_Type_Value_Request:
                    return parseHCI_LE_ExtEvent_ATT_Find_By_Type_Value_Request(parsLen, buffer);

                case (ushort)HCIVendorSpecificEventEventOpcode.ATT_Read_Characteristic_Blob_Value_Request:
                    return parseHCI_LE_ExtEvent_ATT_Read_Characteristic_Blob_Value_Request(parsLen, buffer);

                // HCIEXT

                case (ushort)HCIVendorSpecificEventEventOpcode.HCIEXT_SystemReset:
                    return parseHCI_LE_ExtEvent_HCIEXT_SystemReset(parsLen, buffer);
            }

            return null;
        }


        private static byte parseByteParameter(byte[] buffer, ref byte bufIdx)
        {
            byte parValue = buffer[bufIdx];
            bufIdx++;

            return parValue;
        }

        private static sbyte parseSByteParameter(byte[] buffer, ref byte bufIdx)
        {
            sbyte parValue = (sbyte)buffer[bufIdx];
            bufIdx++;

            return parValue;
        }

        private static ushort parseWordParameter(byte[] buffer, ref byte bufIdx)
        {
            ushort parValue = (ushort)(buffer[bufIdx] + (buffer[bufIdx + 1] << 8));
            bufIdx += 2;

            return parValue;
        }

        private static byte[] parseBufferParameter(byte dataLen, byte[] buffer, ref byte bufIdx)
        {
            if (dataLen == 0) return new byte[0];

            byte[] parBuf = new byte[dataLen];

            Array.Copy(buffer, bufIdx, parBuf, 0, dataLen);

            bufIdx += dataLen;

            return parBuf;
        }
    }
}